﻿using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SolutionOrchestrator.Validators;
using TestProject1.Properties;

namespace TestProject1
{
	[TestClass]
	public class UnitTest1
	{
		class Node : IEnumerable<Node>
		{
			readonly Node[] _subNodes;

			public Node(string label, IEnumerable<Node> subNodes)
			{
				_subNodes = subNodes.ToArray();
				Label = label;
			}

			public string Label { get; private set; }

			public Node this[int i]
			{
				get
				{
					return _subNodes[i];
				}
			}

			public IEnumerator<Node> GetEnumerator()
			{
				return ((IEnumerable<Node>)_subNodes).GetEnumerator();
			}

			IEnumerator IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}

			public string[] Labels
			{
				get { return _subNodes.Select(x => x.Label).ToArray(); }
			}
		}

		class PathSplitted
		{
			PathSplitted(string path)
			{
				Parts = path.Split(new[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries);
			}

			public readonly string[] Parts;

			public static PathSplitted Wrapper(string path)
			{
				return new PathSplitted(path);
			}
		}

		IEnumerable<Node> MakeTree(IEnumerable<string> arr)
		{
			return Level(0, arr.Select(PathSplitted.Wrapper).ToArray());
		}

		IEnumerable<Node> Level(int level, IEnumerable<PathSplitted> paths)
		{
			return paths.GroupBy(x => x.Parts.Length > level ? x.Parts[level] : null).Where(g => g.Key != null).Select(g => new Node(g.Key, Level(level + 1, g)));
		}

		[TestMethod]
		public void Should_make_tree_from_list()
		{
			var arr = new[]
			{
				@"..\..\_dlls\MyUtils\MyUtils3.dll",
				@"..\..\_dlls\MyUtils\MyUtils4.dll",
				@"..\..\_dlls\MyUtils\XTrace3.dll",
				@"..\..\_dlls\MyUtils\XTrace4.dll",
				@"..\..\_dlls\MetaCreator\MetaCreator.dll",
				@"..\..\_dlls\MetaCreator\MetaCreatorTools.dll",
				@"..\..\_dlls\Test.dll",
			};

			var nodes = MakeTree(arr).ToArray();

			CollectionAssert.AreEqual(new[]
			{
				@"..",
			}, nodes.Select(x=>x.Label).ToArray());

			CollectionAssert.AreEqual(new[]
			{
				@"..",
			}, nodes[0].Labels);

			CollectionAssert.AreEqual(new[]
			{
				@"_dlls",
			}, nodes[0][0].Labels);

			CollectionAssert.AreEqual(new[]
			{
				@"MyUtils",
				@"MetaCreator",
				@"Test.dll",
			}, nodes[0][0][0].Labels);

			CollectionAssert.AreEqual(new[]
			{
				@"MyUtils3.dll",
				@"MyUtils4.dll",
				@"XTrace3.dll",
				@"XTrace4.dll",
			}, nodes[0][0][0][0].Labels);

			CollectionAssert.AreEqual(new[]
			{
				@"MetaCreator.dll",
				@"MetaCreatorTools.dll",
			}, nodes[0][0][0][1].Labels);



			Assert.Inconclusive();

		}


		[TestMethod]
		public void Should_detect_correct_reference()
		{
			// Setup
			Directory.CreateDirectory("SampleProject\\bin");
			Directory.CreateDirectory("_libs");
			File.WriteAllText("SampleProject\\SampleProject1.csproj", Resources.SampleProject1);
			File.WriteAllText("SampleProject\\SampleProject2.csproj", Resources.SampleProject2);
			File.WriteAllText("_libs\\MyUtils4.dll", "");
			File.WriteAllText("_libs\\XTrace4.dll", "");
			File.WriteAllText("_libs\\MySpring4.dll", "");
			File.WriteAllText("SampleProject\\bin\\XTrace4.dll", "");

			var file1 = Path.GetFullPath("SampleProject\\SampleProject1.csproj");
			var file2 = Path.GetFullPath("SampleProject\\SampleProject2.csproj");
			var ctx = new ValidationContext {SolutionDir = Directory.GetCurrentDirectory()};

			var br = new BadReferences();
			var violations = br.Validate(file1, ctx).Concat(br.Validate(file2, ctx)).ToArray();
			Assert.AreEqual(3, violations.Length);

			var vi1 = violations.First(x => x.Description.Contains("MyUtils"));
			var vi2 = violations.First(x => x.Description.Contains("XTrace"));
			var vi3 = violations.First(x => x.Description.Contains("MySpring"));

			Assert.AreEqual(file2, vi1.FullPath);

			var fixable1 = vi1 as FixableViolation;
			Assert.IsNotNull(fixable1);
			Assert.AreEqual(1, fixable1.FixesCount);
			Assert.AreEqual("..\\_libs\\MyUtils4.dll", fixable1.FixesAvailable.Single().ToString());

			Assert.AreEqual(file2, vi2.FullPath);

			var fixable2 = vi2 as FixableViolation;
			Assert.IsNotNull(fixable2);
			Assert.AreEqual(1, fixable2.FixesCount);
			Assert.AreEqual("..\\_libs\\XTrace4.dll", fixable2.FixesAvailable.Single().ToString());

			var fixable3 = vi3 as FixableViolation;
			Assert.IsNotNull(fixable3);
			Assert.IsNotNull(fixable3.DefaultFix);
			Assert.IsTrue(fixable3.DefaultExists);
			Assert.AreEqual("..\\_libs\\MySpring4.dll", fixable3.DefaultFix.ToString());

		}

		[TestMethod]
		public void TestMethod1()
		{
			File.WriteAllText("test.xml", Resources.DDM_PerformerWorkplace_OutlookAddIn);
			var doc = new XmlDoc("test.xml");
			var actual = BadReferences.GetReferences(doc, null).ToArray();

			//CollectionAssert.AreEquivalent()
			Assert.AreEqual(23, actual.Length);


			var sys = actual.FirstOrDefault(x => x.Include == "System");
			Assert.IsNotNull(sys);
			Assert.IsTrue(sys.IsGac);

			var platform = actual.FirstOrDefault(x => x.Include.StartsWith("DocsVision.Platform,"));
			Assert.IsNotNull(platform);
			Assert.IsFalse(platform.IsGac);
		}

		[TestMethod]
		public void Should_calc_hint()
		{
			Assert.AreEqual(@"C:\W\_lib\utils\some.dll", BadReferences.Reference.CalcAbsoluteHint(@"..\_lib\utils\some.dll", @"C:\W\P1\my.proj"));
			Assert.AreEqual(null, BadReferences.Reference.CalcAbsoluteHint(@"..\..\..\..\..\..\..\_lib\utils\some.dll", @"C:\W\P1\my.proj"));
			Assert.AreEqual(@"X:\_lib\utils\some.dll", BadReferences.Reference.CalcAbsoluteHint(@"X:\_lib\utils\some.dll", @"C:\W\P1\my.proj"));
		}

	}
}
